#include <QGridLayout>
#include <QtCore/qregularexpression.h>
#include <QtWidgets/QApplication>
#include <data_display/accountDataDialog.h>
#include <utils/hashes.h>
#include "utils/enums.h"


namespace data_display {
accountDataDialog::accountDataDialog(utils::ClipboardWatcher& clipboard_watcher, QWidget *parent, const std::shared_ptr<crypto::cipherManager>& manager)
	: QDialog(parent), _manager(manager), _clipboard_watcher(clipboard_watcher) {
	_item = std::make_shared<crypto::SecureDataMapItem>();
	_item->setManager(_manager);
	auto formGridLayout = new QGridLayout( this );


	_serviceNameEdit = new QLineEdit(this);
	_loginEdit = new QLineEdit(this);
	_passwordEdit = new QLineEdit(this);
	_passwordEdit->setEchoMode(QLineEdit::PasswordEchoOnEdit);
	auto *action = _passwordEdit->addAction(QIcon(":/resources/generatePasswordBlue.png"), QLineEdit::TrailingPosition);

	connect(action, SIGNAL(triggered(bool)), this, SLOT(generatePassword()));
	_secureNoteEdit = new QPlainTextEdit(this);

	_serviceNameLabel = new QLabel(this);
	_serviceNameLabel->setText("Название сервиса");
	_serviceNameLabel->setBuddy(_serviceNameEdit);
	_loginLabel = new QLabel(this);
	_loginLabel->setText("Логин");
	_loginLabel->setBuddy(_loginEdit);
	_passwordLabel = new QLabel(this);
	_passwordLabel->setText("Пароль");
	_passwordLabel->setBuddy(_passwordEdit);
	_passwordWarning = new QLabel(this);
	_passwordWarning->setVisible(false);
	_passwordWarning->setStyleSheet("QLabel {color : red;}");
	_secureNoteLabel = new QLabel(this);
	_secureNoteLabel->setText("Секретная заметка");
	_secureNoteLabel->setBuddy(_secureNoteEdit);

	// initialize buttons
	_buttonBox = new QDialogButtonBox( this );
	_buttonBox->addButton(QDialogButtonBox::Ok );
	_buttonBox->addButton(QDialogButtonBox::Cancel);
	_buttonBox->button(QDialogButtonBox::Ok)->setText("Добавить данные");


	_buttonBox->button(QDialogButtonBox::Cancel)->setText("Выйти");

	connect(_buttonBox->button( QDialogButtonBox::Ok ),
			SIGNAL (clicked()), this, SLOT (createData()));

	connect(_passwordEdit, SIGNAL(textChanged(const QString &)),
		this, SLOT(isPasswordSecure(const QString&)));

	connect(_buttonBox->button( QDialogButtonBox::Cancel) ,
		SIGNAL (clicked()), this, SLOT (reject()));

	formGridLayout->addWidget(_serviceNameLabel, 0, 1);
	formGridLayout->addWidget(_serviceNameEdit, 0, 2);
	formGridLayout->addWidget(_loginLabel, 1, 1);
	formGridLayout->addWidget(_loginEdit, 1, 2);
	formGridLayout->addWidget(_passwordLabel, 2,1);
	formGridLayout->addWidget(_passwordEdit, 2,2);
	formGridLayout->addWidget(_passwordWarning,3,2);
	formGridLayout->addWidget(_secureNoteLabel, 5, 1);
	formGridLayout->addWidget(_secureNoteEdit, 6, 1, 2,2);
	formGridLayout->addWidget( _buttonBox, 8, 0, 1, 0);

	setLayout(formGridLayout);
	setModal(true);
	setWindowTitle("Добавление новой учетной записи");
}

accountDataDialog::accountDataDialog(utils::ClipboardWatcher& clipboard_watcher, QWidget *parent, crypto::SecureDataMapItem *account) : QDialog(parent), _item(account), _clipboard_watcher(clipboard_watcher) {
	auto formGridLayout = new QGridLayout( this );
	auto service_name = account->getDecryptedData(utils::SERVICE_NAME);
	auto login = account->getDecryptedData(utils::LOGIN);
	_serviceNameEdit = new QLineEdit(this);

	_serviceNameEdit->setText(service_name);
	_loginEdit = new QLineEdit(this);
	_loginEdit->setText(login);
	_passwordEdit = new QLineEdit(this);
	_passwordEdit->setEchoMode(QLineEdit::PasswordEchoOnEdit);
	_passwordEdit->setText(QString::fromStdString(account->getEncryptedData(utils::PASSWORD)));
	_passwordEdit->addAction(QIcon("qrc:/resources/generatePasswordBlue.png"), QLineEdit::TrailingPosition);
	_passwordEdit->installEventFilter(this);
	_secureNoteEdit = new QPlainTextEdit(this);
	_secureNoteEdit->setPlainText(account->getDecryptedData(utils::NOTES));

	_serviceNameLabel = new QLabel(this);
	_serviceNameLabel->setText("Название сервиса");
	_serviceNameLabel->setBuddy(_serviceNameEdit);
	_loginLabel = new QLabel(this);
	_loginLabel->setText("Логин");
	_loginLabel->setBuddy(_loginEdit);
	_passwordLabel = new QLabel(this);
	_passwordLabel->setText("Пароль");
	_passwordLabel->setBuddy(_passwordEdit);
	_passwordWarning = new QLabel(this);
	_passwordWarning->setVisible(false);
	_passwordWarning->setStyleSheet("QLabel {color : red;}");
	_secureNoteLabel = new QLabel(this);
	_secureNoteLabel->setText("Секретная заметка");
	_secureNoteLabel->setBuddy(_secureNoteEdit);

	_buttonBox = new QDialogButtonBox( this );
	_buttonBox->addButton(QDialogButtonBox::Ok );
	_buttonBox->addButton(QDialogButtonBox::Cancel);

	_buttonBox->button(QDialogButtonBox::Ok)->setText("Изменить данные");
	_buttonBox->button(QDialogButtonBox::Cancel)->setText("Выйти");

	connect(_buttonBox->button( QDialogButtonBox::Ok ),
			SIGNAL (clicked()), this, SLOT (updateData()));

	connect(_buttonBox->button( QDialogButtonBox::Cancel) ,
		SIGNAL (clicked()), this, SLOT (reject()));

	formGridLayout->addWidget(_serviceNameLabel, 0, 1);
	formGridLayout->addWidget(_serviceNameEdit, 0, 2);
	formGridLayout->addWidget(_loginLabel, 1, 1);
	formGridLayout->addWidget(_loginEdit, 1, 2);
	formGridLayout->addWidget(_passwordLabel, 2,1);
	formGridLayout->addWidget(_passwordEdit, 2,2);
	formGridLayout->addWidget(_passwordWarning,3,2);
	formGridLayout->addWidget(_secureNoteLabel, 5, 1);
	formGridLayout->addWidget(_secureNoteEdit, 6, 1, 2,2);
	formGridLayout->addWidget( _buttonBox, 8, 0, 1, 0);

	setLayout(formGridLayout);
	setModal(true);
	isPasswordSecure(account->getDecryptedData(utils::PASSWORD));
	setWindowTitle("Учетная запись " +  service_name + ":" + login);
}



void accountDataDialog::showPass() {
	_passwordEdit->setEchoMode(QLineEdit::PasswordEchoOnEdit);
}

void accountDataDialog::updateData() {
	if(checkLineEditsNonEmpty()) {
		_item->setDecryptedData(utils::SERVICE_NAME, _serviceNameEdit->text());
		_item->setDecryptedData(utils::LOGIN, _loginEdit->text());
		_item->setDecryptedData(utils::PASSWORD, _passwordEdit->text());
		_item->setDecryptedData(utils::NOTES, _secureNoteEdit->toPlainText());
		close();
	}
}

void accountDataDialog::createData() {
	if(checkLineEditsNonEmpty()) {
		_item->setDecryptedData(utils::SERVICE_NAME, _serviceNameEdit->text());
		_item->setDecryptedData(utils::LOGIN, _loginEdit->text());
		_item->setDecryptedData(utils::PASSWORD, _passwordEdit->text());
		_item->setDecryptedData(utils::NOTES, _secureNoteEdit->toPlainText());
		emit sendData(*_item);
		close();
	}
}

void accountDataDialog::generatePassword() {
	Botan::AutoSeeded_RNG rng;

	// Определяем набор символов, из которых будет состоять пароль
	const std::string charset =
		"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+";

	std::string password;
	password.reserve(16);

	for (int i = 0; i < 16; ++i) {
		// Генерируем случайное число для выбора символа из набора
		uint8_t random_byte = rng.next_byte();
		// Нормализуем случайное число в диапазоне от 0 до длины набора символов
		size_t index = random_byte % charset.size();
		password += charset[index];
	}

	_pop_up = new utils::PopUp(QWidget::geometry(), this);
	_pop_up->setPopupText("Пароль скопирован");
	_pop_up->show();
	_clipboard_watcher.setClipboardData(QString::fromStdString(password));
	_passwordEdit->setText(QString::fromStdString(password));
	emit sendDataCopied();
	QTimer *timer = new QTimer(this);
	_passwordEdit->setEchoMode(QLineEdit::Normal);

	// Подключаем сигнал timeout к лямбда-функции, которая будет менять EchoMode
	connect(timer, &QTimer::timeout, [=]() {
		// При срабатывании таймера меняем режим отображения текста в QLineEdit
			_passwordEdit->setEchoMode(QLineEdit::Password);
	});

	// Запускаем таймер, например, каждые 5 секунд
	timer->start(5000); // 5000 миллисекунд = 5 секунд
}

bool accountDataDialog::checkLineEditsNonEmpty() {
	return not _serviceNameEdit->text().isEmpty() && not _loginEdit->text().isEmpty()
		&& not _passwordEdit->text().isEmpty();
}


bool accountDataDialog::eventFilter(QObject *obj, QEvent *event) {
	if (obj == _passwordEdit) {
		if (event->type() == QEvent::MouseButtonPress) {
			QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
			if (mouseEvent->button() == Qt::LeftButton) {
				if (!waitForDoubleClick) {
					waitForDoubleClick = true;
					QTimer::singleShot(QApplication::doubleClickInterval(), this, [this]() {
						if (waitForDoubleClick) {
							emit sendDataCopied();
							_pop_up = new utils::PopUp(QWidget::geometry(), this);
							_pop_up->setPopupText("Пароль скопирован");
							_pop_up->show();
							_clipboard_watcher.setClipboardData(_item->getDecryptedData(utils::PASSWORD));
							waitForDoubleClick = false;
						}
					});
				}
				return true;
			}
		} else if (event->type() == QEvent::MouseButtonDblClick) {
			waitForDoubleClick = false; // Сброс при двойном клике
			_passwordEdit->setReadOnly(false); // Разрешить редактирование
			return true;
		}
	}
	return QDialog::eventFilter(obj, event);

}

void accountDataDialog::isPasswordSecure(const QString& password) {
	QRegularExpression regex("[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]");
	if (password.length() < 8) {
		_passwordWarning->setText("Пароль должен содержать не менее 8 символов.");
		_passwordWarning->setVisible(true);
	} else if (!password.contains(QRegularExpression("\\d"))) {
		_passwordWarning->setText("Пароль должен содержать хотя бы одну цифру.");
		_passwordWarning->setVisible(true);
	} else if (!password.contains(QRegularExpression("[A-Z]"))) {
		_passwordWarning->setText("Пароль должен содержать хотя бы одну заглавную букву.");
		_passwordWarning->setVisible(true);
	} else if (!password.contains(QRegularExpression("[a-z]"))) {
		_passwordWarning->setText("Пароль должен содержать хотя бы одну строчную букву.");
		_passwordWarning->setVisible(true);
	} else if (!password.contains(regex)) {
		_passwordWarning->setText("Пароль должен содержать хотя бы один специальный символ.");
		_passwordWarning->setVisible(true);
	} else if (utils::getHashes().contains(password.toStdString())) {
		_passwordWarning->setText("Пароль содержится в базе нерекомендуемых паролей.");
		_passwordWarning->setVisible(true);
	} else {
		_passwordWarning->setVisible(false);
	}
}
}
